<template>
    <div>
        <div class="validate-inout-container pb-3">
            <input  
            class="form-control" 
            v-if="tag === 'input'"
            :class="{ 'is-invalid': inputRef.error }" 
            :value="inputRef.val"
            @blur="validateInput"
            @input="updateValue"
            v-bind="$attrs"
            >
            <textarea
            rows="10"
            v-else="tag === 'textarea'"
            class="form-control" 
            :class="{ 'is-invalid': inputRef.error }" 
            :value="inputRef.val"
            @blur="validateInput"
            @input="updateValue"
            v-bind="$attrs"
            />
            <span v-if="inputRef.error" class="invalid-feedback">{{ inputRef.message }}</span>
        </div>
    </div>
</template>
<script lang="ts" setup>
import { PropType,defineProps, reactive} from 'vue';
import {defineEmits,onMounted} from 'vue'
import { RulesProp } from '@/utlis/type';
import { emitter } from '@/utlis/emit';
// 1、邮箱和密码的正则表达式
const emailReg = /^[a-zA-Z0-9.!#$%&’*+/=?^_`{|}~-]+@[a-zA-Z0-9-]+(?:\.[a-zA-Z0-9-]+)*$/
const passwordReg = /^\d+$/
type TagType = 'input' | 'textarea'
// 2、获取从父组件传递过来的数据
const props = defineProps({
    rules: {
        type: Array as PropType<RulesProp>,
        required:true
    },
    modelValue:String,
    tag:{
        type: String as PropType<TagType>,
        default:'input',
    }
})
// 3、禁止透明属性传递,为了显示默认文字
inheritAttrs:false
// 4、双向绑定的输入框inputRef的数据
const inputRef = reactive({
    val:props.modelValue || '',
    error:false,
    message:''
})
// 6、挂载的时候发起事件总线将函数传送过去
if (emitter) {
    onMounted(() => {
        emitter.emit('form-item-created',validateInput)
    })
}
// 7、当触发@blur时，进行格式校验
const validateInput = () => {
    if (props.rules) {
        //默认所有的规则都可以通过
        inputRef.error = false
        //遍历数组中的每一项
        for (const rule of props.rules) {
            switch (rule.type) {
                //当为required时，若输入的数据为空，则错误为true，显示为空的错误信息
                case 'required':
                    if (inputRef.val.trim() == '') {
                        inputRef.error = true,
                        inputRef.message = rule.message
                        return false
                    }
                    break;
                //当为email时，若输入的格式不满足正则表达式，则错误信息为true，显示格式不正确的错误信息
                case 'email':
                    if (!emailReg.test(inputRef.val)) {
                        inputRef.error = true,
                        inputRef.message = rule.message
                        return false
                    }
                    break;
                //若输入的密码不满足正则表达式，则错误信息为true，显示格式不正确的错误信息
                case 'password':
                    if(!passwordReg.test(inputRef.val)){
                        inputRef.error = true,
                        inputRef.message = rule.message
                        return false
                    }
                    break;
                //判断密码的长度范围，当小于6或大于12时，显示错误信息
                case 'range':
                    if(rule.min && rule.max){
                        if(rule.min !== undefined && inputRef.val.length < rule.min){
                            inputRef.error = true,
                            inputRef.message = rule.message
                            return false
                        }
                        if(rule.max !== undefined && inputRef.val.length > rule.max){
                            inputRef.error = true,
                            inputRef.message = rule.message
                            return false
                        }
                    } 
                    break;
                case 'custom':
                    console.log("进行确认密码的检查")
                    if(rule.validator){
                        const isValid = rule.validator()
                        if(!isValid){
                            inputRef.error = true,
                            inputRef.message = rule.message
                            console.log("错误信息：",rule.message)
                            return false
                        }
                    }
                break;
                default:
                    break;
            }

        }
    }
    return true
}
// 8、父子组件的数据连接，父组件使用v-model进行双向绑定，子组件使用属性（接收父组件的数据）+ 自定义事件（向父组件传递数据）
const emit = defineEmits(['update:modelValue']);
const updateValue = (e:Event) =>{
    const targetValue = (e.target as HTMLInputElement).value
    inputRef.val = targetValue
    emit('update:modelValue',targetValue)
}

</script>
<style>

</style>